<template>
  <div ref="wrapRef" :class="getWrapperClass">
    <template v-if="getBindValues.useSearchForm">
      <AdSearchForm
        ref="formRef"
        v-bind="getSearchFormProps"
        @register="registerSearchForm"
        @search-click="handleSearchClick"
      />
    </template>
    <template v-else-if="getBindValues.formConfig">
      <BasicForm
        ref="formRef"
        submitOnReset
        v-bind="getFormProps"
        :tableAction="tableAction"
        @register="registerForm"
        @submit="handleSearchInfoChange"
        @advanced-change="redoHeight"
      >
        <template #[replaceFormSlotKey(item)]="data" v-for="item in getFormSlotKeys">
          <slot :name="item" v-bind="data || {}"></slot>
        </template>
      </BasicForm>
    </template>

    <Table
      ref="tableElRef"
      v-bind="getBindValues"
      :rowClassName="getRowClassName"
      v-show="getEmptyDataIsShowTable"
      @change="handleTableChange"
      @resize-column="handleResizeColumn"
      @expand="handleTableExpand"
    >
      <template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
        <slot :name="item" v-bind="data || {}"></slot>
      </template>
      <template #headerCell="{ column }">
        <slot name="headerCell" v-bind="{ column }">
          <HeaderCell :column="column" />
        </slot>
      </template>
      <template #bodyCell="data">
        <slot name="bodyCell" v-bind="data || {}"></slot>
      </template>
    </Table>

    <AdDetailFormModal @register="registerDetailModal" v-bind="getDetailFormProps" />
  </div>
</template>
<script lang="ts" setup>
  import type { SizeType, ColumnChangeParam } from '@/components/Table/src/types/table';

  import { ref, computed, unref, toRaw, inject, watch, useAttrs, useSlots } from 'vue';
  import { Table } from 'ant-design-vue';
  import { BasicForm, useForm } from '@/components/Form/index';
  import { PageWrapperFixedHeightKey } from '@/enums/pageEnum';
  import HeaderCell from '@/components/Table/src/components/HeaderCell.vue';
  import { InnerHandlers, InnerMethods } from '@/components/Table/src/types/table';

  import { usePagination } from '@/components/Table/src/hooks/usePagination';
  // import { useColumns } from '@/components/Table/src/hooks/useColumns';
  // import { useDataSource } from '@/components/Table/src/hooks/useDataSource';
  import { useLoading } from '@/components/Table/src/hooks/useLoading';
  import { useRowSelection } from '@/components/Table/src/hooks/useRowSelection';
  import { useTableScroll } from '@/components/Table/src/hooks/useTableScroll';
  import { useTableScrollTo } from '@/components/Table/src/hooks/useScrollTo';
  import { useCustomRow } from '@/components/Table/src/hooks/useCustomRow';
  import { useTableStyle } from '@/components/Table/src/hooks/useTableStyle';
  import { useTableHeader } from '@/components/Table/src/hooks/useTableHeader';
  import { useTableExpand } from '@/components/Table/src/hooks/useTableExpand';
  import { createTableContext } from '@/components/Table/src/hooks/useTableContext';
  import { useTableFooter } from '@/components/Table/src/hooks/useTableFooter';
  import { useTableForm } from '@/components/Table/src/hooks/useTableForm';
  import { useDesign } from '@/hooks/web/useDesign';
  import { omit, debounce } from 'lodash-es';
  import { useElementSize } from '@vueuse/core';
  import { isFunction } from '@/utils/is';

  import { useModal } from '@/components/AdVxeModal';
  import { FormModeEnum } from '@/enums/formEnum';

  import { FilterGroup } from '#/request';

  import type { AdTableProps, AdTableActionType } from '@/components/AdTable/src/types/adTable';
  import { adTableProps } from '@/components/AdTable/src/props';
  import { useAdColumns } from '@/components/AdTable/src/hooks/useAdColumns';
  import { useAdDataSource } from '@/components/AdTable/src/hooks/useAdDataSource';
  import { useAdSearchForm } from '@/components/AdTable/src/hooks/useAdSearchForm';
  import { useAdDetailForm } from '@/components/AdTable/src/hooks/useAdDetailForm';
  import AdSearchForm from '@/components/AdTable/src/components/AdSearchForm.vue';
  import AdDetailFormModal from '@/components/AdTable/src/components/AdDetailFormModal.vue';

  defineOptions({ name: 'AdTable' });
  const props = defineProps(adTableProps);
  const emit = defineEmits([
    'fetch-success',
    'fetch-error',
    'selection-change',
    'register',
    'row-click',
    'row-dbClick',
    'row-contextmenu',
    'row-mouseenter',
    'row-mouseleave',
    'edit-end',
    'edit-cancel',
    'edit-row-end',
    'edit-change',
    'expanded-rows-change',
    'change',
    'columns-change',
  ]);
  const attrs = useAttrs();
  const slots = useSlots();

  const tableElRef = ref(null);
  const tableData = ref([]);

  const wrapRef = ref(null);
  const formRef = ref(null);
  const innerPropsRef = ref<Partial<AdTableProps>>();

  const { height } = useElementSize(wrapRef);

  const { prefixCls } = useDesign('basic-table');
  const [registerForm] = useForm();

  const getProps = computed(() => {
    return { ...props, ...unref(innerPropsRef) } as AdTableProps;
  });

  const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false);

  const { getLoading, setLoading } = useLoading(getProps);
  const { getPaginationInfo, getPagination, setPagination, setShowPagination, getShowPagination } =
    usePagination(getProps);

  const {
    getRowSelection,
    getRowSelectionRef,
    getSelectRows,
    setSelectedRows,
    clearSelectedRowKeys,
    getSelectRowKeys,
    deleteSelectRowByKey,
    setSelectedRowKeys,
  } = useRowSelection(getProps, tableData, emit);

  const {
    getSearchFormProps,
    register: registerSearchForm,
    methods: searchFormActions,
  } = useAdSearchForm(getProps, getLoading);

  const {
    handleTableChange: onTableChange,
    getDataSourceRef,
    getDataSource,
    getRawDataSource,
    getSearchInfo,
    setTableData,
    updateTableDataRecord,
    deleteTableDataRecord,
    insertTableDataRecord,
    findTableDataRecord,
    fetch,
    getRowKey,
    reload,
    getAutoCreateKey,
    updateTableData,
  } = useAdDataSource(
    getProps,
    {
      tableData,
      getPaginationInfo,
      setLoading,
      setPagination,
      getSearchInfo: searchFormActions.getSearchInfo,
      clearSelectedRowKeys,
    },
    emit,
  );

  function handleTableChange(pagination: any, filters: any, sorter: any, extra: any) {
    onTableChange(pagination, filters, sorter);
    emit('change', pagination, filters, sorter);
    // 解决通过useTable注册onChange时不起作用的问题
    const { onChange } = unref(getProps);
    onChange && isFunction(onChange) && onChange(pagination, filters, sorter, extra);
  }

  const {
    getViewColumns,
    getColumns,
    setCacheColumnsByField,
    setCacheColumns,
    // setColumnWidth,
    setColumns,
    getColumnsRef,
    getCacheColumns,
  } = useAdColumns(getProps, getPaginationInfo);

  const { getScrollRef, redoHeight } = useTableScroll(
    getProps,
    tableElRef,
    getColumnsRef,
    getRowSelectionRef,
    getDataSourceRef,
    wrapRef,
    formRef,
  );

  const debounceRedoHeight = debounce(redoHeight, 50);

  const { scrollTo } = useTableScrollTo(tableElRef, getDataSourceRef);

  const { customRow } = useCustomRow(getProps, {
    setSelectedRowKeys,
    // @ts-ignore
    getSelectRowKeys,
    clearSelectedRowKeys,
    getAutoCreateKey,
    emit,
  });

  const { getRowClassName } = useTableStyle(getProps, prefixCls);

  const { getExpandOption, expandAll, expandRows, collapseRows, collapseAll, handleTableExpand } =
    useTableExpand(getProps, tableData, emit);

  const handlers: InnerHandlers = {
    onColumnsChange: (data: ColumnChangeParam[]) => {
      emit('columns-change', data);
      // support useTable
      unref(getProps).onColumnsChange?.(data);
    },
  };

  const methods: InnerMethods = {
    clearSelectedRowKeys,
    getSelectRowKeys,
  };

  const { getHeaderProps } = useTableHeader(getProps, slots, handlers, methods);

  const { getFooterProps } = useTableFooter(getProps, getScrollRef, tableElRef, getDataSourceRef);

  const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } =
    // @ts-ignore
    useTableForm(getProps, slots, fetch, getLoading);

  const getBindValues = computed(() => {
    const dataSource = unref(getDataSourceRef);
    let propsData: any = {
      ...attrs,
      customRow,
      ...unref(getProps),
      ...unref(getHeaderProps),
      scroll: unref(getScrollRef),
      loading: unref(getLoading),
      tableLayout: 'fixed',
      rowSelection: unref(getRowSelectionRef),
      rowKey: unref(getRowKey),
      columns: toRaw(unref(getViewColumns)),
      pagination: toRaw(unref(getPaginationInfo)),
      dataSource,
      footer: unref(getFooterProps),
      ...unref(getExpandOption),
    };
    // if (slots.expandedRowRender) {
    //   propsData = omit(propsData, 'scroll');
    // }

    propsData = omit(propsData, ['class', 'onChange']);
    return propsData;
  });

  const getWrapperClass = computed(() => {
    const values = unref(getBindValues);
    return [
      prefixCls,
      attrs.class,
      {
        [`${prefixCls}-form-container`]: values.useSearchForm,
        [`${prefixCls}--inset`]: values.inset,
      },
    ];
  });

  const getEmptyDataIsShowTable = computed(() => {
    const { emptyDataIsShowTable, useSearchForm } = unref(getProps);
    if (emptyDataIsShowTable || !useSearchForm) {
      return true;
    }
    return !!unref(getDataSourceRef).length;
  });

  watch(height, () => {
    unref(isFixedHeightPage) && props.canResize && debounceRedoHeight();
  });

  function setProps(props: Partial<AdTableProps>) {
    innerPropsRef.value = { ...unref(innerPropsRef), ...props };
  }

  const tableAction: AdTableActionType = {
    openDetailForm,
    // @ts-ignore
    reload,
    getSelectRows,
    setSelectedRows,
    clearSelectedRowKeys,
    getSelectRowKeys,
    deleteSelectRowByKey,
    setPagination,
    setTableData,
    updateTableDataRecord,
    deleteTableDataRecord,
    insertTableDataRecord,
    findTableDataRecord,
    redoHeight,
    setSelectedRowKeys,
    setColumns,
    setLoading,
    getDataSource,
    getRawDataSource,
    getSearchInfo,
    // @ts-ignore
    setProps,
    getRowSelection,
    getPaginationRef: getPagination,
    getColumns,
    getCacheColumns,
    emit,
    updateTableData,
    setShowPagination,
    getShowPagination,
    setCacheColumnsByField,
    expandAll,
    collapseAll,
    expandRows,
    collapseRows,
    scrollTo,
    getSize: () => {
      return unref(getBindValues).size as SizeType;
    },
    setCacheColumns,
  };
  createTableContext({ ...tableAction, wrapRef, getBindValues });

  defineExpose({ tableElRef, ...tableAction });

  //详情表单
  const { getDetailFormProps } = useAdDetailForm(getProps, reload);
  // console.log('getDetailFormProps', getDetailFormProps);
  const [registerDetailModal, detailModalMethods] = useModal();

  emit('register', tableAction, searchFormActions, detailModalMethods);

  /** 处理搜索按钮点击 */
  function handleSearchClick(info: FilterGroup) {
    const { handleSearchInfoFn } = unref(getProps);
    if (handleSearchInfoFn && isFunction(handleSearchInfoFn)) {
      info = handleSearchInfoFn(info) || info;
    }
    fetch({ searchInfo: info, page: 1 });
  }

  /** 打开详情表单 */
  function openDetailForm(formMode: FormModeEnum, record?: any) {
    //TODO:高级详情表单的弹窗
    detailModalMethods.openModal(true, {
      formMode: formMode,
      record: record,
    });
  }

  /** 拖动列时触发 */
  function handleResizeColumn(w: any, col: any) {
    // console.log('handleResizeColumn', { w, col });
    col.width = w;
  }
</script>

<style lang="less">
  .ant-table-thead > tr > th {
    text-align: center !important;
  }
</style>
<style lang="less" scoped>
  @border-color: #cecece4d;

  @prefix-cls: ~'@{namespace}-basic-table';

  [data-theme='dark'] {
    .ant-table-tbody > tr:hover.ant-table-row-selected > td,
    .ant-table-tbody > tr.ant-table-row-selected td {
      background-color: #262626;
    }
  }

  .@{prefix-cls} {
    max-width: 100%;
    height: 100%;

    &-row__striped {
      td {
        background-color: @app-content-background !important;
      }
    }

    &-form-container {
      // padding: 16px;

      .ant-form {
        width: 100%;
        // margin-bottom: 16px;
        padding: 12px 10px 6px;
        border-radius: 2px;
        background-color: @component-background;
      }
    }

    .ant-table-cell {
      .ant-tag {
        margin-right: 0;
      }
    }

    .ant-table-wrapper {
      padding: 6px;
      border-radius: 2px;
      background-color: @component-background;

      .ant-table-title {
        min-height: 40px;
        padding: 0 0 8px !important;
      }

      .ant-table.ant-table-bordered .ant-table-title {
        border: none !important;
      }
    }

    .ant-table {
      width: 100%;
      overflow-x: hidden;

      &-title {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 8px 6px;
        border-bottom: none;
      }

      //.ant-table-tbody > tr.ant-table-row-selected td {
      //background-color: fade(@primary-color, 8%) !important;
      //}
    }

    .ant-table-wrapper .ant-pagination {
      margin: 10px 0 0;
    }

    .ant-table-footer {
      padding: 0;

      .ant-table-wrapper {
        padding: 0;
      }

      table {
        border: none !important;
      }

      .ant-table-body {
        overflow-x: hidden !important;
        //  overflow-y: scroll !important;
      }

      td {
        padding: 12px 8px;
      }
    }

    &--inset {
      .ant-table-wrapper {
        padding: 0;
      }
    }
  }
</style>
